package com.ikingtech.framework.sdk.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.io.Serial;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author tie yan
 */
@Slf4j
public class SpEL {

    private SpEL() {

    }

    private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();

    private static final DefaultParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();

    private static final String RESPONSE_DATA_PREFIX = "_res";

    private final EvaluationContext context = new StandardEvaluationContext();

    public static SpEL init(Method method, Object[] args) {
        return init(method, args, null);
    }

    public static SpEL init(Method method, Object[] args, Object proceedResult) {
        SpEL spEl = new SpEL();
        String[] params = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
        if (null == params || params.length == 0) {
            throw new SpELException();
        }
        for (int i = 0; i < params.length; i++) {
            spEl.context.setVariable(params[i], args[i]);
        }
        if (null != proceedResult) {
            spEl.context.setVariable(RESPONSE_DATA_PREFIX, proceedResult);
        }
        return spEl;
    }

    public Object parse(String expression) {
        if (Tools.Str.isNotBlank(expression) && expression.startsWith("#")) {
            try {
                return Objects.requireNonNull(EXPRESSION_PARSER.parseExpression(expression.replace("#", "")).getValue(this.context)).toString();
            } catch (Exception e) {
                log.info("parse expression fail[{}]", expression);
            }
        }
        return expression;
    }

    public static class SpELException extends RuntimeException {

        @Serial
        private static final long serialVersionUID = -5844835902571076396L;
    }
}
